#ifndef UnstructMG_DIRECT_SOLVER_HPP
#define UnstructMG_DIRECT_SOLVER_HPP

#include "common.hpp"

#ifdef __aarch64__
#include "tydss.h"
#elif defined(__x86_64__)
#include "mkl_pardiso.h"
#endif

template<typename idx_t, typename data_t>
class ROW {
public:
    idx_t rid = -1;
    std::vector<idx_t> col_idx;
    std::vector<data_t> vals;
    ROW() { col_idx.clear(); vals.clear(); }
    bool operator < (const ROW & b) const {
        assert(rid != b.rid);
        return rid < b.rid;
    }
};


template<typename idx_t, typename data_t, typename res_t>
class CSR_sparseMat {
public:
    const int root_pid;
    enum PATTERN{SYMMETRIC_POSITIVE_DEFINITE, SYMMETRIC, STRUCTURAL_SYMMETRIC, NONSYMMETRIC, 
            C_HERMITIAN_POSITIVE_DEFINITE, C_HERMITIAN, C_SYMMETRIC, C_STRUCTURAL_SYMMETRIC, C_NONSYMMETRIC};
    idx_t nrows = 0;
    idx_t * row_ptr = nullptr;
    idx_t * col_idx = nullptr;
    data_t* vals = nullptr;
#ifdef __aarch64__
    Tydss::Solver solver;
    Tydss::Matrix A;
    Tydss::Matrix B;
    Tydss::Matrix X;
    int  nthreads;
    int  nthreadsFR;
    int  isComplex;
    int  pattern;
    bool stable;
#elif defined(__x86_64__)
    MKL_INT mtype = 1;
    MKL_INT nrhs = 1;
    void * pt[64];// internal solver memory pointer
    MKL_INT iparm[64];// pardiso control parameters
    MKL_INT maxfct, mnum, phase, error, msglvl;
    double ddum;// Double dummy
    MKL_INT idum;// Integer dummy.
#endif
    CSR_sparseMat(int root_pid, idx_t m, idx_t * Ai, idx_t * Aj, data_t * Av);
    ~CSR_sparseMat();
    bool initSolver(const int nthreads, bool stable, int isComplex);
    bool initA(int isComplex, PATTERN pattern);
    bool initB(const idx_t nrhs, int isComplex);
    bool initX(const idx_t nrhs, int isComplex);
    void analyse(const idx_t nrhs, int swm, int wm, const int nthreads, const int nthreadsFR, const int dynamic=1);
    void factorize(double pert);
    void apply(res_t* b, res_t* x, int refine);
    void fprint_COO(const char * filename) const;
};

typedef CSR_sparseMat<int, double, double> CSR_sparseMat_I32All64;
typedef CSR_sparseMat<int, float , float > CSR_sparseMat_I32All32;

#endif